%%% ------------------------------------------------------------------ 
%%% Licensed under the Apache License, Version 2.0 (the 'License');
%%%  you may not use this file except in compliance with the License.
%%%  You may obtain a copy of the License at
%%%
%%%      http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Copyright (c) 2016-2018 qingchuduwi <bypf2009@vip.qq.com>
%%%
%%%  Unless required by applicable law or agreed to in writing, software
%%%  distributed under the License is distributed on an 'AS IS' BASIS,
%%%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%%  See the License for the specific language governing permissions and
%%%  limitations under the License.
%%%
%%% @doc  DNS host domain
%%% @author  qingchuduwi <'bypf2009@vip.qq.com'> 
%%% @copyright 2016-2018 qingchuduwi <bypf2009@vip.qq.com>
%%% @end
%%% created|changed : 2018-01-02 10:09
%%% coding : utf-8 
%%% ------------------------------------------------------------------ 
-module(dns).
-author("qingchuduwi").

-export([change_ip/2, change_ip/3]).

-spec change_ip(Domain, Addr) -> ok when
        Domain :: binary(),
        Addr   :: binary().
change_ip(Domain, Addr) ->
    change_ip("/home/work/hosts", Domain, Addr).

-spec change_ip(File, Domain, Addr) -> ok when
        File   :: binary()|string(),
        Domain :: binary(),
        Addr   :: binary().
change_ip(File, Domain, Addr) when (is_binary(File) orelse is_list(File))
                              andalso is_binary(Domain)
                              andalso is_binary(Addr) ->
    {ok, Hosts} = file:read_file(File),
    % io:format("~p:~p  hosts:~n~s.",[?MODULE, ?LINE, Hosts]),
    Domains = re:split(Hosts, "\n"),
    NewDomainAddr = replace(Domains, Domain, Addr),
    NewHosts = binary:list_to_bin(NewDomainAddr),
    file:write_file(File, NewHosts).

-spec replace(Domains, Domain, Addr) -> NDomains when
        Domains :: list(),
        Domain  :: binary(),
        Addr    :: binary(),
        NDomains:: list().
replace(Domains, Domain, Addr) ->
    case is_in(Domains, Domain) of
        true ->
            Domains2 =
            lists:foldl(
                fun (DomainAddr, Acc) ->
                        List = re:split(DomainAddr, "[\t ]"),
                        case lists:member(Domain, List) of
                            true ->
                                [_|Tail] = List,
                                NewDomainAddr = binary:list_to_bin([Addr, "  ", Tail]),
                                [NewDomainAddr, "\n" | Acc];
                            false ->
                                [DomainAddr, "\n" | Acc]
                        end
                end, [], Domains),
            [_|Domains3] = lists:reverse(Domains2),
            Domains3;
        false ->
            Domains2 = [<<Addr/binary, "    ", Domain/binary>> | Domains],
            [<<DomainT/binary, "\n">> || DomainT <- Domains2]
    end.


-spec is_in(Domains, Domain) -> Boolean when
        Domains :: list(),
        Domain  :: binary(),
        Boolean :: boolean().
is_in([H | Domains], Domain) ->
    L = re:split(H, "[\t ]"),
    case lists:member(Domain, L) of
        true  -> true;
        false -> is_in(Domains, Domain)
    end;

is_in(_,_) -> false.